/* $Id: plugin_[NIAFC]T-1.sma,v 1.0 by [NIAFC]T ... http://www.niafc.de $
 
denCAT.cfg: 1 filename per line... cat/grep access to this file will be denied...
	    useful for users.ini, server.cfg ( if it contains the rcon_password), etc
denWRITE.cfg: 1 filename per line... write/del access to this file will be denied...
 
admin_write  	append/overwrite a file line
admin_delline 	delete a file line
admin_delfile 	delete a file
admin_resetfile reset a file
admin_cat	cat a file
admin_grep	pattern matching cat
 
aehm before i forget..... it's currently only tested under win32, but it should work for linux too ...
*/
 
#include <core>
#include <console>
#include <string>
#include <admin>
#include <adminlib>
 
#define ACCESS_CAT 4096
#define ACCESS_DEL 4096
#define ACCESS_WRITE 4096
 
new STRING_VERSION[MAX_DATA_LENGTH] = "2.5.0.2";
 
 
public admin_delline(HLCommand,HLData,HLUserName,UserIndex) {
	new tdata[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];
	convert_string(HLData,tdata,MAX_NAME_LENGTH);
	convert_string(HLUserName,User,MAX_NAME_LENGTH);
 
	new tfile[MAX_NAME_LENGTH], tLineNoStr[MAX_NAME_LENGTH], tdeletedLine[MAX_DATA_LENGTH],tmpLine[MAX_DATA_LENGTH];
	new X=1,Y=1,tLineCount=0,tLineNo=0,tDeleted=0;
 
	strbreak(tdata,tfile,tLineNoStr, MAX_NAME_LENGTH);
	if(strlen(tfile) <= 0) {
		selfmessage("[ERROR]: filename missing");
		return PLUGIN_HANDLED;
	}
	if (fileexists(tfile) != 1) {
		selfmessage("[ERROR]: file does not exist");
		return PLUGIN_HANDLED;
	}
	tLineCount = filesize(tfile);
	if (tLineCount < 1) {
		selfmessage("[ERROR]: file is empty");
		return PLUGIN_HANDLED;
	}
	if(strlen(tLineNoStr) <= 0) {
		selfmessage("[ERROR]: line number missing");
		return PLUGIN_HANDLED;
	} 
	tLineNo=strtonum(tLineNoStr);
	if (!(tLineNo > 0 && tLineNo <= tLineCount)) {
		selfmessage("[ERROR]: invalid line number");
		return PLUGIN_HANDLED;
	}
	if (tCheckFileAccess(tfile, 0,User)!=1) return PLUGIN_HANDLED;
	strinit(tdeletedLine);
        if (fileexists("tdel.tmp") != 1) { resetfile("tdel.tmp"); } // Normally it shoudn't... but just in case....
	for (Y=1;Y<=tLineCount;Y++) {
		strinit(tmpLine);
		X=readfile(tfile,tmpLine,Y,MAX_DATA_LENGTH);
		if (X==1) {
			if (Y!=tLineNo) {
				writefile("tdel.tmp",tmpLine);
			} else {
				snprintf(tdeletedLine,MAX_DATA_LENGTH,"%s",tmpLine);
				tDeleted=1;
			}
		}
	}
	if (tDeleted==1) {
		resetfile(tfile);
		tLineCount=filesize("tdel.tmp");
		for (Y=1;Y<=tLineCount;Y++) {
			strinit(tmpLine);
			X=readfile("tdel.tmp",tmpLine,Y,MAX_DATA_LENGTH);
			if (X==1) {
				writefile(tfile,tmpLine);
			}
		}
		deletefile("tdel.tmp");
		snprintf(tmpLine,MAX_DATA_LENGTH,"[INFO]: line no. %i deleted. Deleted line:",tLineNo);
		selfmessage(tmpLine);
		selfmessage(tdeletedLine);
	} else {
		snprintf(tmpLine,MAX_DATA_LENGTH,"[ERROR]: line no. %i not found !",tLineNo);
		selfmessage(tmpLine);
	}
	return PLUGIN_HANDLED;
}
 
public admin_delfile(HLCommand,HLData,HLUserName,UserIndex) {
	new tdata[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];
	convert_string(HLData,tdata,MAX_NAME_LENGTH);
	convert_string(HLUserName,User,MAX_NAME_LENGTH);
	new X;
	new tmp[MAX_DATA_LENGTH];
	if(strlen(tdata) <= 0) {
		selfmessage("[ERROR]: filename missing !");
		return PLUGIN_HANDLED;
	}
	if (fileexists(tdata) != 1) {
		selfmessage("[ERROR]: file does not exist");
		return PLUGIN_HANDLED;
	}
	if (tCheckFileAccess(tdata, 0,User)!=1) return PLUGIN_HANDLED;
        X=deletefile(tdata);
	if (X==1) {
		snprintf(tmp,MAX_DATA_LENGTH,"[INFO]: file '%s' deleted.", tdata);	
	} else {
		snprintf(tmp,MAX_DATA_LENGTH,"[ERROR]: unknown error occured ! file '%s' not deleted !", tdata);	
		selfmessage(tmp);
		snprintf(tmp,MAX_DATA_LENGTH,"[INFO]: error code: %i", X);	
	}
	selfmessage(tmp);	
	return PLUGIN_HANDLED;
}
public admin_resetfile(HLCommand,HLData,HLUserName,UserIndex) {
	new tdata[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];
	convert_string(HLData,tdata,MAX_NAME_LENGTH);
	convert_string(HLUserName,User,MAX_NAME_LENGTH);
	new X;
	new tmp[MAX_DATA_LENGTH];
	if(strlen(tdata) <= 0) {
		selfmessage("[ERROR]: filename missing !");
		return PLUGIN_HANDLED;
	}
	if (fileexists(tdata) != 1) {
		selfmessage("[ERROR]: file does not exist");
		return PLUGIN_HANDLED;
	}
	if (tCheckFileAccess(tdata, 0,User)!=1) return PLUGIN_HANDLED;
        X=resetfile(tdata);
	if (X==1) {
		snprintf(tmp,MAX_DATA_LENGTH,"[INFO]: file '%s' cleared.", tdata);	
	} else {
		snprintf(tmp,MAX_DATA_LENGTH,"[ERROR]: unknown error occured ! file '%s' not cleared !", tdata);	
		selfmessage(tmp);
		snprintf(tmp,MAX_DATA_LENGTH,"[INFO]: error code: %i", X);	
	}
	selfmessage(tmp);	
	return PLUGIN_HANDLED;
}
 
 
public admin_write(HLCommand,HLData,HLUserName,UserIndex) {
	new tdata[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];
	convert_string(HLData,tdata,MAX_NAME_LENGTH);
	convert_string(HLUserName,User,MAX_NAME_LENGTH);
 
	new tfile[MAX_NAME_LENGTH], tLineNoStr[MAX_NAME_LENGTH], tmp[MAX_DATA_LENGTH], tmpLine[MAX_DATA_LENGTH],tToWrite[MAX_DATA_LENGTH];
	new X=1,tLineCount=0,tLineNo=0;
 
	strbreak(tdata,tfile,tmpLine, MAX_NAME_LENGTH);
	if(strlen(tfile) <= 0) {
		selfmessage("[ERROR]: filename missing !");
		return PLUGIN_HANDLED;
	}
 
	strbreak(tmpLine,tLineNoStr,tToWrite, MAX_NAME_LENGTH);
	if(strlen(tLineNoStr) <= 0) {
		selfmessage("[ERROR]: line number missing ( use 0 for appending ) !");
		return PLUGIN_HANDLED;
	}
	tLineNo=strtonum(tLineNoStr);
	if (fileexists(tfile) != 1) {
		selfmessage("[INFO]: file does not exist. file will be created.");
	} else {
		tLineCount = filesize(tfile);	
		if (!(tLineNo >= 0 && tLineNo <= tLineCount)) {
			selfmessage("[ERROR]: invalid line number !");
			return PLUGIN_HANDLED;
		}
	}
	if (tCheckFileAccess(tfile, 0,User)!=1) return PLUGIN_HANDLED;
	if (tLineNo > 0) {
		X=readfile(tfile,tmpLine,tLineNo,MAX_DATA_LENGTH);
		if (X==1) {
			X=writefile(tfile,tToWrite,tLineNo);
			if (X==1) {
				snprintf(tmp,MAX_DATA_LENGTH,"[INFO]: line no. %i (file '%s') replaced.",tLineNo,tfile);
				selfmessage(tmp);
				selfmessage("old line:");
				selfmessage(tmpLine);
				selfmessage("new line:");
				selfmessage(tToWrite);
			} else {
				selfmessage("[ERROR]: unknown file error occured !");
			}
		} else {
			selfmessage("[ERROR]: invalid line number !");
		}
	} else {
		X=writefile(tfile,tToWrite);
		if (X==1) {
			snprintf(tmp,MAX_DATA_LENGTH,"[INFO]: line appended (file '%s').",tfile);
			selfmessage(tmp);
			selfmessage("new line: ");
			selfmessage(tToWrite);
		} else {
			selfmessage("[ERROR]: unknown file error occured !");
		}
	}
 
	return PLUGIN_HANDLED;
}
 
tCheckFileAccess(tfile[], accesstype, User[])   //accesstype: 1=read, 2=write
{
	new TConfFile[MAX_DATA_LENGTH],tmpLine[MAX_DATA_LENGTH];
	new LCountCfg,X,Y;
	strinit(TConfFile);
	if (fileexists(tfile)!=1) {
		return 1;
	}
	if (accesstype==1) strcat(TConfFile,"denCAT.cfg",MAX_DATA_LENGTH);
	else strcat(TConfFile,"denWRITE.cfg",MAX_DATA_LENGTH);
	LCountCfg=filesize(TConfFile);
	if (LCountCfg<1) {
		selfmessage("[WARNING]: no restricted files configured");
		if (accesstype==1) {
			selfmessage("[WARNING]: all files can be cat !!!");
			selfmessage("[WARNING]: please configure 'denCAT.cfg' for more security..");
		} else {
			selfmessage("[WARNING]: all files can be changed !!!");
			selfmessage("[WARNING]: please configure 'denWRITE.cfg' for more security..");
		}
	} else {
		for(X=1;X<=LCountCfg;X++) {
			strinit(tmpLine);
			Y=readfile(TConfFile,tmpLine,X,MAX_DATA_LENGTH);
			if (Y>0) {
				if (streq(tmpLine,tfile)==1) {
					snprintf(tmpLine,MAX_DATA_LENGTH,"[INFO]: Sorry %s, %s ", User, tfile);
					if (accesstype==1) {
						snprintf(tmpLine,MAX_DATA_LENGTH,"%s is read-protected !", tmpLine);	
					} else {
						snprintf(tmpLine,MAX_DATA_LENGTH,"%s is write-protected !", tmpLine);	
					}
 					selfmessage(tmpLine);
					return 0;
				}
			}
		}
	}
	return 1;
}
public admin_cat(HLCommand,HLData,HLUserName,UserIndex) {
	new tdata[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];
	convert_string(HLData,tdata,MAX_NAME_LENGTH);
	convert_string(HLUserName,User,MAX_NAME_LENGTH);
 
	new tmpLine[MAX_DATA_LENGTH], tfile[MAX_NAME_LENGTH], TPageStr[MAX_NAME_LENGTH], TOptions[MAX_NAME_LENGTH];
	new X=1,Y=1,TShowLineNo=1,TPageIndex=0,LineCount=0;
 
	strbreak(tdata,tfile,tmpLine, MAX_NAME_LENGTH);
	TOptions[0]=NULL_CHAR;
	strbreak(tmpLine,TPageStr,TOptions, MAX_NAME_LENGTH);
	if(strlen(tfile) <= 0) {
		selfmessage("[ERROR]: filename missing");
		return PLUGIN_HANDLED;
	}
	if (fileexists(tfile) != 1) {
		selfmessage("[ERROR]: file does not exist");
		return PLUGIN_HANDLED;
	}
	LineCount = filesize(tfile);
	if (LineCount < 1) {
		selfmessage("[ERROR]: file is empty");
		return PLUGIN_HANDLED;
	}
	if(strlen(TPageStr) <= 0) {
		selfmessage("[ERROR]: page number missing");
		return PLUGIN_HANDLED;
	} 
	if(TOptions[0] != NULL_CHAR) TShowLineNo=0;
	TPageIndex=strtonum(TPageStr);
 
 
        new TotalPages;
	TotalPages= LineCount / 20;
	if ((LineCount % 20) > 0) TotalPages++;
	if ((!(TPageIndex > 0)) || ((TPageIndex*20)-19 > LineCount)) {
		snprintf(tmpLine,MAX_DATA_LENGTH,"[ERROR]: invalid page number, you must enter a number between 1 and %i", TotalPages);
		selfmessage(tmpLine);
		return PLUGIN_HANDLED;
	}
	if (tCheckFileAccess(tfile, 1,User)!=1) return PLUGIN_HANDLED;
	snprintf(tmpLine,MAX_DATA_LENGTH,"File: %s  Page: %i/%i", tfile,TPageIndex,TotalPages);
	selfmessage(tmpLine);
	selfmessage("->");
	for(X=(TPageIndex*20)-19;X<=TPageIndex*20;X++) {
			strinit(tmpLine);
			Y=readfile(tfile,tmpLine,X,MAX_DATA_LENGTH);
			if (Y>0) {
			   if (TShowLineNo==1) {
				snprintf(tmpLine,MAX_DATA_LENGTH,"(%i) %s", X, tmpLine);
			   } 
			   selfmessage(tmpLine);
			}
	}
	selfmessage("<-");
 
	return PLUGIN_HANDLED;
}
 
instr(TString[],PartMatch[]) {
	new i=0;
	new TLen = strlen(TString);
	new TLenPart = strlen(PartMatch);
	new j;
	new ret;
	new tmp[MAX_DATA_LENGTH];
	if ((TLen < TLenPart) || (TLenPart < 1)) return 0;
	for(i=0;i<TLen;i++) {
		if (TString[i] == PartMatch[0]) {
			if (i + TLenPart > TLen) return 0;
			strinit(tmp);
			for(j=0;j<TLenPart;j++) tmp[j]=TString[i+j];
			ret = strmatch(tmp,PartMatch,TLenPart);
			if (ret==1) return 1;
		}
	}
	return 0;
}
 
public admin_grep(HLCommand,HLData,HLUserName,UserIndex) {
	new tdata[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];
	convert_string(HLData,tdata,MAX_NAME_LENGTH);
	convert_string(HLUserName,User,MAX_NAME_LENGTH);
 
	new tmp[MAX_DATA_LENGTH], tmp1[MAX_DATA_LENGTH];
	new tpattern[MAX_NAME_LENGTH],TOptions[MAX_NAME_LENGTH], tfile[MAX_NAME_LENGTH], TPageStr[MAX_DATA_LENGTH];
	new LineCount=0,TShowLineNo=1,TPageIndex=0;
 
	strbreak(tdata,tfile,tmp, MAX_NAME_LENGTH);
	strbreak(tmp,tpattern,tmp1, MAX_NAME_LENGTH);
	TOptions[0]= NULL_CHAR;
	strbreak(tmp1,TPageStr,TOptions, MAX_NAME_LENGTH);
	if(strlen(tfile) <= 0) {
		selfmessage("[ERROR]: filename missing");
		return PLUGIN_HANDLED;
	}
	if(strlen(tpattern) <= 0) {
		selfmessage("[ERROR]:  pattern missing");
		return PLUGIN_HANDLED;
	}
	if(strlen(TPageStr) <= 0) {
		selfmessage("[ERROR]:  page number missing");
		return PLUGIN_HANDLED;
	}
	if(TOptions[0] != NULL_CHAR) TShowLineNo=0;
	TPageIndex=strtonum(TPageStr);
	if (fileexists(tfile) != 1) {
		selfmessage("[ERROR]:  file does not exist");
		return PLUGIN_HANDLED;
	}
	LineCount = filesize(tfile);
	if (LineCount < 1) {
		selfmessage("[ERROR]: file is empty");
		return PLUGIN_HANDLED;
	}
	if (tCheckFileAccess(tfile, 1,User)!=1) return PLUGIN_HANDLED; 
 
	snprintf(tmp,MAX_DATA_LENGTH,"File: %s Pattern: %s", tfile, tpattern);
	selfmessage(tmp);
	selfmessage("->");
	new X=1;
	new Y=1;
	new TFound=0;
	while(X!=0) {
		strinit(tmp);
		X=readfile(tfile,tmp,Y,MAX_DATA_LENGTH);
		if (X>0) {
			if (instr(tmp,tpattern)==1) {
				TFound++;
				if ((TFound<=TPageIndex*20) && (TFound>=(TPageIndex*20)-19)) {
					if (TShowLineNo==1) {
						snprintf(tmp,MAX_DATA_LENGTH,"(%i) %s",Y, tmp);
					}
					selfmessage(tmp);
				}
			}
		}
		Y++;	
	}
	selfmessage("<--");
	new TotalPages;
	TotalPages= TFound / 20;
	if ((TFound % 20) > 0) TotalPages++;
	if (TPageIndex > TotalPages) {
		snprintf(tmp,MAX_DATA_LENGTH,"[ERROR]: invalid page number %i.",TPageIndex);
		selfmessage(tmp);
		snprintf(tmp,MAX_DATA_LENGTH,"[INFO]: total page count: %i.",TotalPages);
		selfmessage(tmp);
	} else {
		snprintf(tmp,MAX_DATA_LENGTH,"total match(es): %i Page: %i/%i",TFound, TPageIndex,TotalPages);
		selfmessage(tmp);
	}
	return PLUGIN_HANDLED;
}
 
public plugin_init() {
	plugin_registerinfo("[NIAFC]T-Adminmod Plugin","[NIAFC]T's admin file functions",STRING_VERSION);
	plugin_registercmd("admin_cat","admin_cat",ACCESS_CAT,"admin_cat <file> <page> [<^"1^" | ^"0^">]:  cat the <file> and show page <page> with or without linenumbers");
	plugin_registercmd("admin_delline","admin_delline",ACCESS_DEL,"admin_delline <file> <linenumer>:  deletes a line in a file");
	plugin_registercmd("admin_delfile","admin_delfile",ACCESS_DEL,"admin_delfile <file>:  deletes the file <file>");
	plugin_registercmd("admin_resetfile","admin_resetfile",ACCESS_DEL,"admin_resetfile <file>:  clears the file <file>");
	plugin_registercmd("admin_write","admin_write",ACCESS_WRITE,"admin_write <file> <linenumer (0 = append)> <linetowrite>:  appends/replaces a line in a file");
	plugin_registercmd("admin_grep","admin_grep",ACCESS_CAT,"admin_grep <file> <pattern> <page> [<^"1^" | ^"0^">]:  grep <file> and show patternmatched lines on page <page> with or without linenumbers");
	return PLUGIN_CONTINUE;
}